package com.a0soft.gphone.aTruffleHog.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;

public class CrashHandler {
    private static Thread.UncaughtExceptionHandler m_default = null;
    private static CrashReportHandler m_onUnknownErrors;
    private static boolean m_bShowSystemCrashDialog = true;
    private static volatile boolean m_bCrashing;
    private static String m_strDeveloperEmail, m_strAppName, m_strDID, m_strPkgInfo;
    
    private static final String LOG_TAG = CrashHandler.class.getSimpleName();
    
    public static void
    Init(Context ctx, 
         String strDeveloperEmail, 
         boolean bShowSystemCrashDialog)
    {
        m_strDeveloperEmail = strDeveloperEmail;
    
        m_strAppName = ctx.getApplicationInfo()
                          .loadLabel(ctx.getPackageManager()).toString();
        
        if (m_strDeveloperEmail != null) {
            m_bShowSystemCrashDialog = bShowSystemCrashDialog;
    
            m_default = Thread.getDefaultUncaughtExceptionHandler();
            m_onUnknownErrors = new CrashReportHandler();
            Thread.setDefaultUncaughtExceptionHandler(m_onUnknownErrors);
            
            _InitPakageInfo(ctx);
        }
    }
    
    //called by DeviceInfo, when device info is ready
    public static void
    SetDID(String strDID)
    {
        m_strDID = strDID;
    }
    
    public static String
    GetPackageInfo()
    {
        return m_strPkgInfo;        
    }
    
    private static void
    _InitPakageInfo(Context ctx)
    {
        StringBuilder sb = new StringBuilder(2048);
        
        String strPkg = ctx.getPackageName();
        PackageInfo pi;
        try {
            pi = ctx.getPackageManager().getPackageInfo(strPkg, 0);
        }
        catch (NameNotFoundException e) {
            pi = null;
        }
        
        //package information
        sb.append("\npackage info\n=======================\n");
        sb.append("pkg:").append(strPkg).append("\n");
        if (pi != null) {
            sb.append("version name:").append(pi.versionName).append("\n");
            sb.append("version code:").append(pi.versionCode).append("\n");
        }
        if (MiscUtil.GetSDKVersion() >= 8) {
            sb.append("installed on SD:")
              .append(SDK8.GetInstance().IsAppInstalledOnExternalStorage(ctx, strPkg))
              .append("\n");
        }
        
        //system information
        sb.append("\nsystem info\n=======================\n");
        sb.append("manufacture:").append(Build.MANUFACTURER).append("\n");
        sb.append("brand:").append(Build.BRAND).append("\n");
        sb.append("device:").append(Build.DEVICE).append("\n");
        sb.append("model:").append(Build.MODEL).append("\n");
        sb.append("product:").append(Build.PRODUCT).append("\n");
        sb.append("version.release:").append(Build.VERSION.RELEASE).append("\n");
        sb.append("sdk_version:").append(MiscUtil.GetSDKVersion()).append("\n");
        
        m_strPkgInfo = sb.toString();
    }
    
    //////////////////////////////////////////////////////////////////////////////
    private static class CrashReportHandler implements UncaughtExceptionHandler {
        public void uncaughtException(Thread thread, Throwable ex) {
            try {
                // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
                if (m_bCrashing) return;
                m_bCrashing = true;
                
                if (m_strDeveloperEmail != null) {
                    Context ctx = MiscUtil.GetAppContext();
                    
                    StringBuffer sb = new StringBuffer(2048);
                    
                    sb.append("Please help to send this crash report to developer and describe the problem:\n\n\n");

                    sb.append(m_strPkgInfo).append("\n");
                    
                    final Writer result = new StringWriter();
                    final PrintWriter printWriter = new PrintWriter(result);
                    ex.printStackTrace(printWriter);
                    sb.append("Code stack trace\n")
                      .append("=======================\n");
                    sb.append(result.toString());
                    sb.append("=======================\n");
                    printWriter.close();
                    
                    if (m_strDID != null) {
                        sb.append("\nDeveloper can get the detailed device infomation at ")
                          .append(CONFIGURATION.SERVER_URL).append("/device/")
                          .append(m_strDID).append("\n");
                    }
                    
                    //send email
                    Intent it = new Intent(Intent.ACTION_SEND);
                    String[] tos = {m_strDeveloperEmail};
                    it.putExtra(Intent.EXTRA_EMAIL, tos);
                    it.putExtra(Intent.EXTRA_SUBJECT, m_strAppName + " crash report");
                    it.putExtra(Intent.EXTRA_TEXT, sb.toString());
                    it.setType("message/rfc882");
                    
                    //it = Intent.createChooser(it, "Send crash report by");
                    //ctx could be a application context, not activity context, 
                    //so we need to add FLAG_ACTIVITY_NEW_TASK
                    it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
                    ctx.startActivity(it);
                }
                
                if (m_bShowSystemCrashDialog) {
                    //show system crash report dialog
                    if (m_default != null) {
                        m_default.uncaughtException(thread, ex);
                        return;
                    }
                }
            }
            catch (Throwable t) {
                if (aDebug.ENABLED)
                    aDebug.d(LOG_TAG, "", t);
            }

            // Try everything to make sure this process goes away.
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(10);
        }
    }
}
